define("arale/arale-validator/0.11.0/index-debug", ["arale/arale-widget/1.2.0/widget-debug","arale/arale-base/1.2.0/base-debug","arale/arale-class/1.2.0/class-debug","arale/arale-events/1.2.0/events-debug"], function(require, exports, module){

module.exports = require("arale/arale-validator/0.11.0/src/validator-debug");

});
define("arale/arale-validator/0.11.0/src/validator-debug", ["arale/arale-widget/1.2.0/widget-debug","arale/arale-base/1.2.0/base-debug","arale/arale-class/1.2.0/class-debug","arale/arale-events/1.2.0/events-debug"], function(require, exports, module){
var Core = require("arale/arale-validator/0.11.0/src/core-debug"),
    $ = window.jQuery;

var Validator = Core.extend({

    events: {
        'mouseenter .{{attrs.inputClass}}': 'mouseenter',
        'mouseleave .{{attrs.inputClass}}': 'mouseleave',
        'mouseenter .{{attrs.textareaClass}}': 'mouseenter',
        'mouseleave .{{attrs.textareaClass}}': 'mouseleave',
        'focus .{{attrs.itemClass}} input,textarea,select': 'focus',
        'blur .{{attrs.itemClass}} input,textarea,select': 'blur'
    },

    attrs: {
        explainClass: 'ui-form-explain',
        itemClass: 'ui-form-item',
        itemHoverClass: 'ui-form-item-hover',
        itemFocusClass: 'ui-form-item-focus',
        itemErrorClass: 'ui-form-item-error',
        itemSuccessClass: "ui-form-item-success",
        inputClass: 'ui-input',
        textareaClass: 'ui-textarea',

        showMessage: function (message, element) {
            this.getExplain(element).html(message);
            this.getItem(element).addClass(this.get('itemErrorClass'));
        },

        hideMessage: function (message, element) {
            this.getExplain(element).html(element.attr('data-explain') || ' ');

            var parentItem = this.getItem(element);

            parentItem.removeClass(this.get("itemErrorClass"));
            //var successMsg = this.query(element).get("successMsg");
            if (!element.is(":focus")) {
                parentItem.addClass(this.get('itemSuccessClass'));
            }
        }
    },

    setup: function () {
        Validator.superclass.setup.call(this);

        var that = this;

        this.on('autoFocus', function (ele) {
            that.set('autoFocusEle', ele);
        })
    },

    addItem: function (cfg) {
        Validator.superclass.addItem.apply(this, [].slice.call(arguments));
        var item = this.query(cfg.element);
        if (item) {
            this._saveExplainMessage(item);
        }
        return this;
    },

    _saveExplainMessage: function (item) {
        var that = this;
        var ele = item.element;

        var explain = ele.attr('data-explain');
        // If explaining message is not specified, retrieve it from data-explain attribute of the target
        // or from DOM element with class name of the value of explainClass attr.
        // Explaining message cannot always retrieve from DOM element with class name of the value of explainClass
        // attr because the initial state of form may contain error messages from server.
        // ---
        // Also, If explaining message is under ui-form-item-error className
        // it could be considered to be a error message from server
        // that should not be put into data-explain attribute
        if (explain === undefined && !this.getItem(ele).hasClass(this.get('itemErrorClass'))) {
            ele.attr('data-explain', this.getExplain(ele).html());
        }
    },

    getExplain: function (ele) {
        var item = this.getItem(ele);
        var explain = item.find('.' + this.get('explainClass'));

        if (explain.length == 0) {
            explain = $('<div class="' + this.get('explainClass') + '"></div>').appendTo(item);
        }

        return explain;
    },

    getItem: function (ele) {
        ele = $(ele);
        var item = ele.parents('.' + this.get('itemClass'));

        return item;
    },

    mouseenter: function (e) {
        this.getItem(e.target).addClass(this.get('itemHoverClass'));
    },

    mouseleave: function (e) {
        this.getItem(e.target).removeClass(this.get('itemHoverClass'));
    },

    focus: function (e) {
        var target = e.target,
            autoFocusEle = this.get('autoFocusEle');

        if (autoFocusEle && autoFocusEle.has(target)) {
            var that = this;
            $(target).keyup(function (e) {
                that.set('autoFocusEle', null);
                that.focus({target: target});
            });
            return;
        }


        this.getItem(target).removeClass(this.get('itemErrorClass'))
            .removeClass(this.get('itemSuccessClass'))

        this.getItem(target).addClass(this.get('itemFocusClass'));
        this.getExplain(target).html($(target).attr('data-explain') || '');
    },

    blur: function (e) {
        this.getItem(e.target).removeClass(this.get('itemFocusClass'));
    }
});


module.exports = Validator;

});
define("arale/arale-validator/0.11.0/src/core-debug", ["arale/arale-widget/1.2.0/widget-debug","arale/arale-base/1.2.0/base-debug","arale/arale-class/1.2.0/class-debug","arale/arale-events/1.2.0/events-debug"], function(require, exports, module){
var $ = window.jQuery,
    async = require("arale/arale-validator/0.11.0/src/async-debug"),
    Widget = require("arale/arale-widget/1.2.0/widget-debug"),
    utils = require("arale/arale-validator/0.11.0/src/utils-debug"),
    Item = require("arale/arale-validator/0.11.0/src/item-debug");

var validators = [];

var setterConfig = {
    value: $.noop,
    setter: function (val) {
        return $.isFunction(val) ? val : utils.helper(val);
    }
};

var Core = Widget.extend({
    attrs: {
        triggerType: 'blur',
        checkOnSubmit: true,    // 是否在表单提交前进行校验，默认进行校验。
        stopOnError: false,     // 校验整个表单时，遇到错误时是否停止校验其他表单项。
        autoSubmit: true,       // When all validation passed, submit the form automatically.
        checkNull: true,        // 除提交前的校验外，input的值为空时是否校验。
        onItemValidate: setterConfig,
        onItemValidated: setterConfig,
        onFormValidate: setterConfig,
        onFormValidated: setterConfig,
        // 此函数用来定义如何自动获取校验项对应的 display 字段。
        displayHelper: function (item) {
            var labeltext, name;
            var id = item.element.attr('id');
            if (id) {
                labeltext = $('label[for="' + id + '"]').text();
                if (labeltext) {
                    labeltext = labeltext.replace(/^[\*\s\:\：]*/, '').replace(/[\*\s\:\：]*$/, '');
                }
            }
            name = item.element.attr('name');
            return labeltext || name;
        },
        showMessage: setterConfig, // specify how to display error messages
        hideMessage: setterConfig, // specify how to hide error messages
        autoFocus: true,           // Automatically focus at the first element failed validation if true.
        failSilently: false,       // If set to true and the given element passed to addItem does not exist, just ignore.
        skipHidden: false          // 如果 DOM 隐藏是否进行校验
    },

    setup: function () {
        // Validation will be executed according to configurations stored in items.
        var self = this;

        self.items = [];

        // 外层容器是否是 form 元素
        if (self.element.is("form")) {
            // 记录 form 原来的 novalidate 的值，因为初始化时需要设置 novalidate 的值，destroy 的时候需要恢复。
            self._novalidate_old = self.element.attr('novalidate');

            // disable html5 form validation
            // see: http://bugs.jquery.com/ticket/12577
            try {
                self.element.attr('novalidate', 'novalidate');
            } catch (e) {}

            //If checkOnSubmit is true, then bind submit event to execute validation.
            if (self.get('checkOnSubmit')) {
                self.element.on("submit.validator", function (e) {
                    e.preventDefault();
                    self.execute(function (err) {
                        !err && self.get('autoSubmit') && self.element.get(0).submit();
                    });
                });
            }
        }

        // 当每项校验之后, 根据返回的 err 状态, 显示或隐藏提示信息
        self.on('itemValidated', function (err, message, element, event) {
            this.query(element).get(err?'showMessage':'hideMessage').call(this, message, element, event);
        });

        validators.push(self);
    },

    Statics: $.extend({helper: utils.helper}, require("arale/arale-validator/0.11.0/src/rule-debug"), {
        autoRender: function (cfg) {

            var validator = new this(cfg);

            $('input, textarea, select', validator.element).each(function (i, input) {

                input = $(input);
                var type = input.attr('type');

                if (type == 'button' || type == 'submit' || type == 'reset') {
                    return true;
                }

                var options = {};

                if (type == 'radio' || type == 'checkbox') {
                    options.element = $('[type=' + type + '][name=' + input.attr('name') + ']', validator.element);
                } else {
                    options.element = input;
                }


                if (!validator.query(options.element)) {

                    var obj = utils.parseDom(input);

                    if (!obj.rule) return true;

                    $.extend(options, obj);

                    validator.addItem(options);
                }
            });
        },

        query: function (selector) {
            return Widget.query(selector);
        },

        // TODO 校验单项静态方法的实现需要优化
        validate: function (options) {
            var element = $(options.element);
            var validator = new Core({
                element: element.parents()
            });

            validator.addItem(options);
            validator.query(element).execute();
            validator.destroy();
        }
    }),


    addItem: function (cfg) {
        var self = this;
        if ($.isArray(cfg)) {
            $.each(cfg, function (i, v) {
                self.addItem(v);
            });
            return this;
        }

        cfg = $.extend({
            triggerType: self.get('triggerType'),
            checkNull: self.get('checkNull'),
            displayHelper: self.get('displayHelper'),
            showMessage: self.get('showMessage'),
            hideMessage: self.get('hideMessage'),
            failSilently: self.get('failSilently'),
            skipHidden: self.get('skipHidden')
        }, cfg);

        // 当 item 初始化的 element 为 selector 字符串时
        // 默认到 validator.element 下去找
        if (typeof cfg.element === 'string') {
            cfg.element = this.$(cfg.element);
        }

        if (!$(cfg.element).length) {
            if (cfg.failSilently) {
                return self;
            } else {
                throw new Error('element does not exist');
            }
        }
        var item = new Item(cfg);

        self.items.push(item);
        // 关联 item 到当前 validator 对象
        item._validator = self;

        item.delegateEvents(item.get('triggerType'), function (e) {
            if (!this.get('checkNull') && !this.element.val()) return;
            this.execute(null, {event: e});
        });

        item.on('all', function (eventName) {
            this.trigger.apply(this, [].slice.call(arguments));
        }, self);

        return self;
    },

    removeItem: function (selector) {
        var self = this,
            target = selector instanceof Item ? selector : self.query(selector);

        if (target) {
            target.get('hideMessage').call(self, null, target.element);
            erase(target, self.items);
            target.destroy();
        }

        return self;
    },

    execute: function (callback) {
        var self = this,
            results = [],
            hasError = false,
            firstElem = null;

        // 在表单校验前, 隐藏所有校验项的错误提示
        $.each(self.items, function (i, item) {
            item.get('hideMessage').call(self, null, item.element);
        });
        self.trigger('formValidate', self.element);

        async[self.get('stopOnError') ? "forEachSeries" : "forEach" ](self.items, function (item, cb) {  // iterator
            item.execute(function (err, message, ele) {
                // 第一个校验错误的元素
                if (err && !hasError) {
                    hasError = true;
                    firstElem = ele;
                }
                results.push([].slice.call(arguments, 0));

                // Async doesn't allow any of tasks to fail, if you want the final callback executed after all tasks finished.
                // So pass none-error value to task callback instead of the real result.
                cb(self.get('stopOnError') ? err : null);

            });
        }, function () {  // complete callback
            if (self.get('autoFocus') && hasError) {
                self.trigger('autoFocus', firstElem);
                firstElem.focus();
            }

            self.trigger('formValidated', hasError, results, self.element);
            callback && callback(hasError, results, self.element);
        });

        return self;
    },

    destroy: function () {
        var self = this,
            len = self.items.length;

        if (self.element.is("form")) {
            try {
                if (self._novalidate_old == undefined)
                    self.element.removeAttr('novalidate');
                else
                    self.element.attr('novalidate', self._novalidate_old);
            } catch (e) {
            }

            self.element.off('submit.validator');
        }

        for (var i = len - 1; i >= 0; i--) {
            self.removeItem(self.items[i]);
        }
        erase(self, validators);

        Core.superclass.destroy.call(this);
    },

    query: function (selector) {
        return findItemBySelector(this.$(selector), this.items);

        // 不使用 Widget.query 是因为, selector 有可能是重复, 选择第一个有可能不是属于
        // 该组件的. 即使 再次使用 this.items 匹配, 也没法找到
        /*var target = Widget.query(selector),
            result = null;
        $.each(this.items, function (i, item) {
            if (item === target) {
                result = target;
                return false;
            }
        });
        return result;*/
    }
});

// 从数组中删除对应元素
function erase(target, array) {
    for(var i=0; i<array.length; i++) {
        if (target === array[i]) {
            array.splice(i, 1);
            return array;
        }
    }
}

function findItemBySelector(target, array) {
    var ret;
    $.each(array, function (i, item) {
        if (target.get(0) === item.element.get(0)) {
            ret = item;
            return false;
        }
    });
    return ret;
}
module.exports = Core;

});
define("arale/arale-validator/0.11.0/src/async-debug", [], function(require, exports, module){
var async = {};

module.exports = async;

//// cross-browser compatiblity functions ////

var _forEach = function (arr, iterator) {
  if (arr.forEach) {
    return arr.forEach(iterator);
  }
  for (var i = 0; i < arr.length; i += 1) {
    iterator(arr[i], i, arr);
  }
};

var _map = function (arr, iterator) {
  if (arr.map) {
    return arr.map(iterator);
  }
  var results = [];
  _forEach(arr, function (x, i, a) {
    results.push(iterator(x, i, a));
  });
  return results;
};

var _keys = function (obj) {
  if (Object.keys) {
    return Object.keys(obj);
  }
  var keys = [];
  for (var k in obj) {
    if (obj.hasOwnProperty(k)) {
      keys.push(k);
    }
  }
  return keys;
};

//// exported async module functions ////

async.forEach = function (arr, iterator, callback) {
  callback = callback || function () {
  };
  if (!arr.length) {
    return callback();
  }
  var completed = 0;
  _forEach(arr, function (x) {
    iterator(x, function (err) {
      if (err) {
        callback(err);
        callback = function () {
        };
      }
      else {
        completed += 1;
        if (completed === arr.length) {
          callback(null);
        }
      }
    });
  });
};

async.forEachSeries = function (arr, iterator, callback) {
  callback = callback || function () {
  };
  if (!arr.length) {
    return callback();
  }
  var completed = 0;
  var iterate = function () {
    iterator(arr[completed], function (err) {
      if (err) {
        callback(err);
        callback = function () {
        };
      }
      else {
        completed += 1;
        if (completed === arr.length) {
          callback(null);
        }
        else {
          iterate();
        }
      }
    });
  };
  iterate();
};

var doParallel = function (fn) {
  return function () {
    var args = Array.prototype.slice.call(arguments);
    return fn.apply(null, [async.forEach].concat(args));
  };
};
var doSeries = function (fn) {
  return function () {
    var args = Array.prototype.slice.call(arguments);
    return fn.apply(null, [async.forEachSeries].concat(args));
  };
};


var _asyncMap = function (eachfn, arr, iterator, callback) {
  var results = [];
  arr = _map(arr, function (x, i) {
    return {index: i, value: x};
  });
  eachfn(arr, function (x, callback) {
    iterator(x.value, function (err, v) {
      results[x.index] = v;
      callback(err);
    });
  }, function (err) {
    callback(err, results);
  });
};
async.map = doParallel(_asyncMap);
async.mapSeries = doSeries(_asyncMap);

async.series = function (tasks, callback) {
  callback = callback || function () {
  };
  if (tasks.constructor === Array) {
    async.mapSeries(tasks, function (fn, callback) {
      if (fn) {
        fn(function (err) {
          var args = Array.prototype.slice.call(arguments, 1);
          if (args.length <= 1) {
            args = args[0];
          }
          callback.call(null, err, args);
        });
      }
    }, callback);
  }
  else {
    var results = {};
    async.forEachSeries(_keys(tasks), function (k, callback) {
      tasks[k](function (err) {
        var args = Array.prototype.slice.call(arguments, 1);
        if (args.length <= 1) {
          args = args[0];
        }
        results[k] = args;
        callback(err);
      });
    }, function (err) {
      callback(err, results);
    });
  }
};

});
define("arale/arale-validator/0.11.0/src/utils-debug", [], function(require, exports, module){
var $ = window.jQuery,
    Rule = require("arale/arale-validator/0.11.0/src/rule-debug");

var u_count = 0;
var helpers = {};


function unique() {
    return '__anonymous__' + (u_count++);
}

function parseRules(str) {
    if (!str) return null;

    return str.match(/[a-zA-Z0-9\-\_]+(\{[^\{\}]*\})?/g);
}

function parseDom(field) {
    var field = $(field);

    var result = {};
    var arr = [];

    //parse required attribute
    var required = field.attr('required');
    if (required) {
        arr.push('required');
        result.required = true;
    }

    //parse type attribute
    var type = field.attr('type');
    if (type && type != 'submit' && type != 'cancel' && type != 'checkbox' && type != 'radio' && type != 'select' && type != 'select-one' && type != 'file' && type != 'hidden' && type != 'textarea') {

        if (!Rule.getRule(type)) {
            throw new Error('Form field with type "' + type + '" not supported!');
        }

        arr.push(type);
    }

    //parse min attribute
    var min = field.attr('min');
    if (min) {
        arr.push('min{"min":"' + min + '"}');
    }

    //parse max attribute
    var max = field.attr('max');
    if (max) {
        arr.push('max{max:' + max + '}');
    }

    //parse minlength attribute
    var minlength = field.attr('minlength');
    if (minlength) {
        arr.push('minlength{min:' + minlength + '}');
    }

    //parse maxlength attribute
    var maxlength = field.attr('maxlength');
    if (maxlength) {
        arr.push('maxlength{max:' + maxlength + '}');
    }

    //parse pattern attribute
    var pattern = field.attr('pattern');
    if (pattern) {
        var regexp = new RegExp(pattern),
            name = unique();
        Rule.addRule(name, regexp);
        arr.push(name);
    }

    //parse data-rule attribute to get custom rules
    var rules = field.attr('data-rule');
    rules = rules && parseRules(rules);
    if (rules)
        arr = arr.concat(rules);

    result.rule = arr.length == 0 ? null : arr.join(' ');

    return result;
}

function parseJSON(str) {
    if (!str)
        return null;

    var NOTICE = 'Invalid option object "' + str + '".';

    // remove braces
    str = str.slice(1, -1);

    var result = {};

    var arr = str.split(',');
    $.each(arr, function (i, v) {
        arr[i] = $.trim(v);
        if (!arr[i])
            throw new Error(NOTICE);

        var arr2 = arr[i].split(':');

        var key = $.trim(arr2[0]),
            value = $.trim(arr2[1]);

        if (!key || !value)
            throw new Error(NOTICE);

        result[getValue(key)] = $.trim(getValue(value));
    });

    // 'abc' -> 'abc'  '"abc"' -> 'abc'
    function getValue(str) {
        if (str.charAt(0) == '"' && str.charAt(str.length - 1) == '"' || str.charAt(0) == "'" && str.charAt(str.length - 1) == "'") {
            return eval(str);
        }
        return str;
    }

    return result;
}

function isHidden (ele) {
    var w = ele[0].offsetWidth,
        h = ele[0].offsetHeight,
        force = (ele.prop('tagName') === 'TR');
    return (w===0 && h===0 && !force) ? true : (w!==0 && h!==0 && !force) ? false : ele.css('display') === 'none';
}

module.exports = {
    parseRule: function (str) {
        var match = str.match(/([^{}:\s]*)(\{[^\{\}]*\})?/);

        // eg. { name: "valueBetween", param: {min: 1, max: 2} }
        return {
            name: match[1],
            param: parseJSON(match[2])
        };
    },
    parseRules: parseRules,
    parseDom: parseDom,
    isHidden: isHidden,
    helper: function (name, fn) {
        if (fn) {
            helpers[name] = fn;
            return this;
        }

        return helpers[name];
    }
};


});
define("arale/arale-validator/0.11.0/src/rule-debug", [], function(require, exports, module){
var $ = window.jQuery,

    rules = {},
    messages = {};

function Rule(name, oper) {
    var self = this;

    self.name = name;

    if (oper instanceof RegExp) {
        self.operator = function (opts, commit) {
            var rslt = oper.test($(opts.element).val());
            commit(rslt ? null : opts.rule, _getMsg(opts, rslt));
        };
    } else if ($.isFunction(oper)) {
        self.operator = function (opts, commit) {
            var rslt = oper.call(this, opts, function (result, msg) {

                //缓存异步请求
                $.data(opts.element,"previousValue", {
                    old: opts.element.val(),
                    msg: msg,
                    valid: result == null ? true : false,
                    err: result ? null : opts.rule
                })

                commit(result ? null : opts.rule, msg || _getMsg(opts, result));
            });
            // 当是异步判断时, 返回 undefined, 则执行上面的 commit
            if (rslt !== undefined) {
                commit(rslt ? null : opts.rule, _getMsg(opts, rslt));
            }
        };
    } else {
        throw new Error('The second argument must be a regexp or a function.');
    }
}

Rule.prototype.and = function (name, options) {
    var target = name instanceof Rule ? name : getRule(name, options);

    if (!target) {
        throw new Error('No rule with name "' + name + '" found.');
    }

    var that = this;
    var operator = function (opts, commit) {
        that.operator.call(this, opts, function (err, msg) {
            if (err) {
                commit(err, _getMsg(opts, !err));
            } else {
                target.operator.call(this, opts, commit);
            }
        });
    };

    return new Rule(null, operator);
};
Rule.prototype.or = function (name, options) {
    var target = name instanceof Rule ? name : getRule(name, options);

    if (!target) {
        throw new Error('No rule with name "' + name + '" found.');
    }

    var that = this;
    var operator = function (opts, commit) {
        that.operator.call(this, opts, function (err, msg) {
            if (err) {
                target.operator.call(this, opts, commit);
            } else {
                commit(null, _getMsg(opts, true));
            }
        });
    };

    return new Rule(null, operator);
};
Rule.prototype.not = function (options) {
    var target = getRule(this.name, options);
    var operator = function (opts, commit) {
        target.operator.call(this, opts, function (err, msg) {
            if (err) {
                commit(null, _getMsg(opts, true));
            } else {
                commit(true, _getMsg(opts, false))
            }
        });
    };

    return new Rule(null, operator);
};


function addRule(name, operator, message) {
    if ($.isPlainObject(name)) {
        $.each(name, function (i, v) {
            if ($.isArray(v))
                addRule(i, v[0], v[1]);
            else
                addRule(i, v);
        });
        return this;
    }

    if (operator instanceof Rule) {
        rules[name] = new Rule(name, operator.operator);
    } else {
        rules[name] = new Rule(name, operator);
    }
    setMessage(name, message);

    return this;
}

function _getMsg(opts, b) {
    var ruleName = opts.rule;
    var msgtpl;

    if (opts.message) { // user specifies a message
        if ($.isPlainObject(opts.message)) {
            msgtpl = opts.message[b ? 'success' : 'failure'];
            // if user's message is undefined，use default
            typeof msgtpl === 'undefined' && (msgtpl = messages[ruleName][b ? 'success' : 'failure']);
        } else {//just string
            msgtpl = b ? '' : opts.message
        }
    } else { // use default
        msgtpl = messages[ruleName][b ? 'success' : 'failure'];
    }

    return msgtpl ? compileTpl(opts, msgtpl) : msgtpl;
}

function setMessage(name, msg) {
    if ($.isPlainObject(name)) {
        $.each(name, function (i, v) {
            setMessage(i, v);
        });
        return this;
    }

    if ($.isPlainObject(msg)) {
        messages[name] = msg;
    } else {
        messages[name] = {
            failure: msg
        };
    }
    return this;
}



function getRule(name, opts) {
    if (opts) {
        var rule = rules[name];
        return new Rule(null, function (options, commit) {
            rule.operator($.extend(null, options, opts), commit);
        });
    } else {
        return rules[name];
    }
}

function compileTpl(obj, tpl) {
    var result = tpl;

    var regexp1 = /\{\{[^\{\}]*\}\}/g,
        regexp2 = /\{\{(.*)\}\}/;

    var arr = tpl.match(regexp1);
    arr && $.each(arr, function (i, v) {
        var key = v.match(regexp2)[1];
        var value = obj[$.trim(key)];
        result = result.replace(v, value);
    });
    return result;
}

addRule('required', function (options) {
    var element = $(options.element);

    var t = element.attr('type');
    switch (t) {
        case 'checkbox':
        case 'radio':
            var checked = false;
            element.each(function (i, item) {
                if ($(item).prop('checked')) {
                    checked = true;
                    return false;
                }
            });
            return checked;
        default:
            return Boolean($.trim(element.val()));
    }
}, '请输入{{display}}');

addRule('email', /^\s*([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,20})\s*$/, '{{display}}的格式不正确');

addRule('text', /.*/);

addRule('password', /.*/);

addRule('radio', /.*/);

addRule('checkbox', /.*/);

addRule('url', /^(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/, '{{display}}的格式不正确');

addRule('number', /^[+-]?[1-9][0-9]*(\.[0-9]+)?([eE][+-][1-9][0-9]*)?$|^[+-]?0?\.[0-9]+([eE][+-][1-9][0-9]*)?$|^0$/, '{{display}}的格式不正确');

// 00123450 是 digits 但不是 number
// 1.23 是 number 但不是 digits
addRule('digits', /^\s*\d+\s*$/, '{{display}}的格式不正确');

addRule('date', /^\d{4}\-[01]?\d\-[0-3]?\d$|^[01]\d\/[0-3]\d\/\d{4}$|^\d{4}年[01]?\d月[0-3]?\d[日号]$/, '{{display}}的格式不正确');

addRule('min', function (options) {
    var element = options.element,
        min = options.min;
    return Number(element.val()) >= Number(min);
}, '{{display}}必须大于或者等于{{min}}');

addRule('max', function (options) {
    var element = options.element,
        max = options.max;
    return Number(element.val()) <= Number(max);
}, '{{display}}必须小于或者等于{{max}}');

addRule('minlength', function (options) {
    var element = options.element;
    var l = element.val().length;
    return l >= Number(options.min);
}, '{{display}}的长度必须大于或等于{{min}}');

addRule('maxlength', function (options) {
    var element = options.element;
    var l = element.val().length;
    return l <= Number(options.max);
}, '{{display}}的长度必须小于或等于{{max}}');

addRule('mobile', /^1\d{10}$/, '请输入正确的{{display}}');

addRule('confirmation', function (options) {
    var element = options.element,
        target = $(options.target);
    return element.val() == target.val();
}, '两次输入的{{display}}不一致，请重新输入');

module.exports = {
    addRule: addRule,
    setMessage: setMessage,
    getMessage: function(options, isSuccess) {
        return _getMsg(options, isSuccess);
    },
    getRule: getRule,
    getOperator: function (name) {
        return rules[name].operator;
    }
};

});
define("arale/arale-validator/0.11.0/src/item-debug", ["arale/arale-widget/1.2.0/widget-debug","arale/arale-base/1.2.0/base-debug","arale/arale-class/1.2.0/class-debug","arale/arale-events/1.2.0/events-debug"], function(require, exports, module){
var $ = window.jQuery,
    utils = require("arale/arale-validator/0.11.0/src/utils-debug"),
    Widget = require("arale/arale-widget/1.2.0/widget-debug"),
    async = require("arale/arale-validator/0.11.0/src/async-debug"),
    Rule = require("arale/arale-validator/0.11.0/src/rule-debug");

var setterConfig = {
    value: $.noop,
    setter: function (val) {
        return $.isFunction(val) ? val : utils.helper(val);
    }
};

function hasRequired(val) {
    return (' ' + val + ' ').indexOf(' required ') >= 0;
}

var Item = Widget.extend({
    attrs: {
        rule: {
            value: '',
            getter: function (val) {
                val = $.trim(val);

                // 在获取的时候动态判断是否required，来追加或者删除 rule: required
                if (this.get('required')) {
                    if (!val || !hasRequired(val)) {
                        val = $.trim('required ' + val);
                    }
                } else {
                    if (hasRequired(val)) {
                        val = $.trim((' ' + val + ' ').replace(' required ', ' '));
                    }
                }

                return val;
            }
        },
        display: null,
        displayHelper: null,
        triggerType: {
            getter: function (val) {
                if (!val)
                    return val;

                var element = this.element,
                    type = element.attr('type');

                // 将 select, radio, checkbox 的 blur 和 key 事件转成 change
                var b = element.is("select") || type == 'radio' || type == 'checkbox';
                if (b && (val.indexOf('blur') > -1 || val.indexOf('key') > -1))
                    return 'change';
                return val;
            }
        },
        required: {
            value: false,
            getter: function (val) {
                return $.isFunction(val) ? val() : val;
            }
        },
        cache: true,
        checkNull: true,
        errormessage: null,
        onItemValidate: setterConfig,
        onItemValidated: setterConfig,
        showMessage: setterConfig,
        hideMessage: setterConfig
    },

    setup: function () {
        if (!this.get('display') && $.isFunction(this.get('displayHelper'))) {
            this.set('display', this.get('displayHelper')(this));
        }
    },

    // callback 为当这个项校验完后, 通知 form 的 async.forEachSeries 此项校验结束并把结果通知到 async,
    // 通过 async.forEachSeries 的第二个参数 Fn(item, cb) 的 cb 参数
    execute: function (callback, context) {
        var self = this,
            elemDisabled = !!self.element.attr("disabled");

        context = context || {};
        // 如果是设置了不检查不可见元素的话, 直接 callback
        if (self.get('skipHidden') && utils.isHidden(self.element) || elemDisabled) {
            callback && callback(null, '', self.element);
            return self;
        }

        self.trigger('itemValidate', self.element, context.event);


        //添加验证缓存
        var previous = self.previousValue(self.element);

        if (self.get("cache") && previous.old === self.element.val()) {
            self.trigger('itemValidated', previous.err, previous.msg, self.element, context.event);
            callback && callback(previous.err, previous.msg, self.element);
            return self;
        }

        var rules = utils.parseRules(self.get('rule'));

        if (rules) {
            _metaValidate(self, rules, function (err, msg) {

                self.trigger('itemValidated', err, msg, self.element, context.event);
                callback && callback(err, msg, self.element);
            });
        } else {
            self.trigger('itemValidated', null, '', self.element, context.event);
            callback && callback(null, '', self.element);
        }

        return self;
    },
    previousValue: function (element, val) {

        return $.data(element, "previousValue") || $.data(element,
                "previousValue", {
                    old: null,
                    valid: false,
                    msg: "",
                    err: null
                })
    },
    getMessage: function (theRule, isSuccess, options) {
        var message = '',
            self = this,
            rules = utils.parseRules(self.get('rule'));

        isSuccess = !!isSuccess;

        $.each(rules, function (i, item) {
            var obj = utils.parseRule(item),
                ruleName = obj.name,
                param = obj.param;

            if (theRule === ruleName) {
                message = Rule.getMessage($.extend(options || {}, getMsgOptions(param, ruleName, self)), isSuccess);
            }
        });
        return message;
    }
});

function getMsgOptions(param, ruleName, self) {
    var options = $.extend({}, param, {
        element: self.element,
        display: (param && param.display) || self.get('display'),
        rule: ruleName
    });

    var message = self.get('errormessage' + upperFirstLetter(ruleName)) || self.get('errormessage');
    if (message && !options.message) {
        options.message = {
            failure: message
        };
    }

    return options;
}

function upperFirstLetter(str) {
    str = str + "";
    return str.charAt(0).toUpperCase() + str.slice(1);
}

function _metaValidate(self, rules, callback) {
    var ele = self.element;

    if (!self.get('required')) {
        var truly = false;
        var t = ele.attr('type');
        switch (t) {
            case 'checkbox':
            case 'radio':
                var checked = false;
                ele.each(function (i, item) {
                    if ($(item).prop('checked')) {
                        checked = true;
                        return false;
                    }
                });
                truly = checked;
                break;
            default:
                truly = !!ele.val();
        }

        // 非必要且没有值的时候, 直接 callback
        if (!truly) {
            callback && callback(null, null);
            return;
        }
    }

    if (!$.isArray(rules))
        throw new Error('No validation rule specified or not specified as an array.');

    var tasks = [];

    $.each(rules, function (i, item) {
        var obj = utils.parseRule(item),
            ruleName = obj.name,
            param = obj.param;

        var ruleOperator = Rule.getOperator(ruleName);
        if (!ruleOperator)
            throw new Error('Validation rule with name "' + ruleName + '" cannot be found.');

        var options = getMsgOptions(param, ruleName, self);

        tasks.push(function (cb) {
            // cb 为 async.series 每个 tasks 函数 的 callback!!
            // callback(err, results)
            // self._validator 为当前 Item 对象所在的 Validator 对象
            ruleOperator.call(self._validator, options, cb);
        });
    });


    // form.execute -> 多个 item.execute -> 多个 rule.operator
    // 多个 rule 的校验是串行的, 前一个出错, 立即停止
    // async.series 的 callback fn, 在执行 tasks 结束或某个 task 出错后被调用
    // 其参数 results 为当前每个 task 执行的结果
    // 函数内的 callback 回调给项校验
    async.series(tasks, function (err, results) {
        callback && callback(err, results[results.length - 1]);
    });
}

module.exports = Item;

});
